#include <iostream>
#include "local.h"

using namespace std;

Local :: Local(){
	Lista< pair <Hamburguesa,Cantidad> > listaComidas;
	pair <Hamburguesa,Cantidad> comida1 (McPato,1);
	pair <Hamburguesa,Cantidad> comida2 (McGyver,1);
	pair <Hamburguesa,Cantidad> comida3 (CukiQueFresco,1);
	pair <Hamburguesa,Cantidad> comida4 (BigMacabra,1);
	listaComidas.agregar(comida1);
	listaComidas.agregar(comida2);
	listaComidas.agregar(comida3);
	listaComidas.agregar(comida4);

	Lista< pair <Bebida,Cantidad> > listaBebidas;
	pair <Bebida,Cantidad> bebida1 (PestiCola,1);
	pair <Bebida,Cantidad> bebida2 (SeVeNada,1);
	pair <Bebida,Cantidad> bebida3 (FalsaNaranja,1);
	pair <Bebida,Cantidad> bebida4 (AguaSinGags,1);
	pair <Bebida,Cantidad> bebida5 (AguaConGags,1);
	listaBebidas.agregar(bebida1);
	listaBebidas.agregar(bebida2);
	listaBebidas.agregar(bebida3);
	listaBebidas.agregar(bebida4);
	listaBebidas.agregar(bebida5);

	Lista< pair <Empleado,Energia> > listaEmpleados;
	pair <Empleado,Energia> empleado1 ("Cacho",100);
	pair <Empleado,Energia> empleado2 ("Carlos",100);
	listaEmpleados.agregar(empleado1);
	listaEmpleados.agregar(empleado2);

	Lista<Pedido> listaPedido;

	_sandwiches = listaComidas;
	_bebidas = listaBebidas;
	_empleados = listaEmpleados;
	_ventas = listaPedido;

}

Local :: Local(const Lista< pair <Bebida,Cantidad> > bs, const Lista< pair <Hamburguesa,Cantidad> > hs, const Lista<Empleado> es){

	Lista< pair <Empleado,Energia> > listaEmpleados;
	int cantE = es.longitud(), i = 0;
	while(i<cantE){
		pair <Empleado,Energia> empleado;
		empleado.first = es.iesimo(i);
		empleado.second = 100;
		listaEmpleados.agregarAtras(empleado);
		i++;
	}

	_bebidas = bs;
	_sandwiches = hs;
	_empleados = listaEmpleados;
}

Cantidad Local :: stockBebidasL(const Bebida b){
	int i = 0, cantB = _bebidas.longitud(), stock;
	bool encontreLaBebida = false;
	while(i<cantB && !encontreLaBebida){
		stock = _bebidas.iesimo(i).second;
		encontreLaBebida = _bebidas.iesimo(i).first == b;
		i++;
	}
	return stock;
}

Cantidad Local :: stockSandwichesL(const Hamburguesa h){
	int i = 0, cantH = _sandwiches.longitud(), stock;
	bool encontreElSanguche = false;
	while(i<cantH && !encontreElSanguche){
		stock = _sandwiches.iesimo(i).second;
		encontreElSanguche = _sandwiches.iesimo(i).first == h;
		i++;
	}
	return stock;
}

Lista<Bebida> Local :: bebidasDelLocalL(){
		Lista<Bebida> listaBebidas;
		int i = 0, cantB = _bebidas.longitud();
		while(i<cantB){
			listaBebidas.agregar(_bebidas.iesimo(i).first);
			i++;
		}
		return listaBebidas;
}

Lista<Hamburguesa> Local :: sandwichesDelLocalL(){
		Lista<Hamburguesa> listaSanguches;
		int i = 0, cantH = _sandwiches.longitud();
		while(i<cantH){
			listaSanguches.agregar(_sandwiches.iesimo(i).first);
			i++;
		}
		return listaSanguches;
}

Lista<Empleado> Local :: empleadosL(){
		Lista<Empleado> listaEmpleados;
		int i = 0, cantE = _empleados.longitud();
		while(i<cantE){
			if(_empleados.iesimo(i).second>=0){
				listaEmpleados.agregar(_empleados.iesimo(i).first);
			}
		i++;
		}
		return listaEmpleados;
}

Lista<Empleado> Local :: desempleadosL(){
		Lista<Empleado> listaDesempleados;
		int i = 0, cantE = _empleados.longitud();
		while(i<cantE){
			if(_empleados.iesimo(i).second<0){
				listaDesempleados.agregar(_empleados.iesimo(i).first);
			}
		i++;
		}
		return listaDesempleados;
}

Energia Local :: energiaEmpleadoL(const Empleado e){
		int i = 0, cantE = _empleados.longitud(), energia;
		bool encontreEmpleado = false;
		while(i<cantE && !encontreEmpleado){
			energia = _empleados.iesimo(i).second;
			encontreEmpleado = _empleados.iesimo(i).first == e;
			i++;
		}
		return energia;
}

Lista<Pedido> Local :: ventasL(){
	return _ventas;
}

bool Local :: unaVentaCadaUnoL(){

		Lista<Empleado> empleadosActivos (empleadosQueVendieron());
		Lista<Empleado> prefijoEmpleados (primerasApariciones(empleadosQueVendieron()));
		int longitud_prefijo = prefijoEmpleados.longitud();
		bool vanAlternados = true;

		while(longitud_prefijo < empleadosActivos.longitud() && vanAlternados){
				vanAlternados = esPrefijo(prefijoEmpleados,empleadosActivos);
				leSacoNelementos(longitud_prefijo,empleadosActivos);
		}

		if(longitud_prefijo >= empleadosActivos.longitud() && vanAlternados){
				int i = 0;
				while(i<empleadosActivos.longitud()){
						vanAlternados = vanAlternados && (empleadosActivos.iesimo(i) == prefijoEmpleados.iesimo(i));
						i++;
				}
		}
		return vanAlternados;
}

void Local :: leSacoNelementos(int n, Lista<Empleado>& listaEmpleados){
		int i = 0;
		while(i < n){
				listaEmpleados.cola();
				i++;
		}
}

bool Local :: esPrefijo(Lista<Empleado> prefijo, Lista<Empleado> listaEmpleados){
		int prefijo_longitud = prefijo.longitud(), i = 0;
		int empleadosV = listaEmpleados.longitud();
		bool esPref = false;
		if(prefijo_longitud<= empleadosV){
			esPref = true;
			while(i<prefijo_longitud){
					esPref = esPref && (prefijo.iesimo(i) == listaEmpleados.iesimo(i));
					i++;
			}
		}
		return esPref;
}

Lista<Empleado> Local :: empleadosQueVendieron(){
		Lista<Empleado> listaEmpleados;
		int i = 0, cantVentas = _ventas.longitud();
		while(i<cantVentas){
			if(empleadosL().pertenece(_ventas.iesimo(i).atendioP())){
			listaEmpleados.agregarAtras(_ventas.iesimo(i).atendioP());
			}
			i++;
		}
		return listaEmpleados;
}

Lista<Empleado> Local :: primerasApariciones(Lista<Empleado> listaEmpleados){
		Lista<Empleado> listaNueva;
		int i = 0, cantE = listaEmpleados.longitud();
		while(i<cantE){
			if(!listaNueva.pertenece(listaEmpleados.iesimo(i))){
				listaNueva.agregarAtras(listaEmpleados.iesimo(i));
			}
			i++;
		}
		return listaNueva;
}

void Local :: venderL(const Pedido p){

	int i = 0;
	int energiaAtiende = energiaEmpleadoL(p.atendioP());
	int difPedido = p.dificultadP();
	int actualizarStock;
	int energiaActual;

	Lista< pair<Bebida,Cantidad> > lasBebidas;
	pair <Bebida, Cantidad> beb_cant;
	Lista< pair<Hamburguesa,Cantidad> > losSanguches;
	pair <Hamburguesa, Cantidad> hamb_cant;
	Lista< pair<Empleado,Energia> > losEmpleados;
	pair<Empleado,Energia> emp_ene;

	if(energiaAtiende >= difPedido){

		_ventas.agregar(p);

		while(i < _bebidas.longitud()){
			beb_cant.first = _bebidas.iesimo(i).first;
			actualizarStock = _bebidas.iesimo(i).second- cantidadBebidaEnElPedido(_bebidas.iesimo(i).first, p);
			beb_cant.second = actualizarStock;
			lasBebidas.agregarAtras(beb_cant);
			i++;
		}

		_bebidas = lasBebidas;


		i = 0;
		while(i < _sandwiches.longitud()){
			hamb_cant.first = _sandwiches.iesimo(i).first;
			actualizarStock = _sandwiches.iesimo(i).second - cantidadSangucheEnElPedido(_sandwiches.iesimo(i).first, p);
			hamb_cant.second = actualizarStock;
			losSanguches.agregarAtras(hamb_cant);
			i++;
		}

		_sandwiches = losSanguches;
	}
		i = 0;
		while(i < _empleados.longitud()){
			emp_ene.first = _empleados.iesimo(i).first;
			energiaActual = _empleados.iesimo(i).second - energiaQuePerdio(_empleados.iesimo(i).first,p);
			emp_ene.second = energiaActual;
			losEmpleados.agregarAtras(emp_ene);
			i++;
		}

		_empleados = losEmpleados;

}

int Local :: cantidadBebidaEnElPedido(Bebida b, const Pedido p){
	int k = 0;
	int cantidadBebida = 0;
	int cantCombos = p.combosP().longitud();
	while(k < cantCombos){
		if(p.combosP().iesimo(k).bebidaC() == b){
			cantidadBebida = cantidadBebida + 1;
		}
		k++;
	}
	return cantidadBebida;
}

int Local :: cantidadSangucheEnElPedido(Hamburguesa h, const Pedido p){
	int k = 0;
	int cantidadSanguche = 0;
	int cantCombos = p.combosP().longitud();
	while(k < cantCombos){
		if(p.combosP().iesimo(k).sandwichC() == h){
			cantidadSanguche = cantidadSanguche + 1;
		}
		k++;
	}
	return cantidadSanguche;
}

int Local :: energiaQuePerdio(Empleado e, const Pedido p){
	int esfuerzo = 0;
	if(p.atendioP()==e){
		esfuerzo = p.dificultadP();
	}
	return esfuerzo;
}

Lista<Empleado> Local :: candidatosAEmpleadosDelMesL(){
        int cantEmpleadosQueMasVendieron = empleadosQueMasPedidosVendieron().longitud(),i=0;
        Lista<Empleado> losQueMasCombosVendieron;
        while(i<cantEmpleadosQueMasVendieron){
            if(cantidadDeCombosQueVendio(empleadosQueMasPedidosVendieron().iesimo(i)) == maximoDeCombosVendidos()){
                losQueMasCombosVendieron.agregarAtras(empleadosQueMasPedidosVendieron().iesimo(i));
            }
            i++;
        }
        return losQueMasCombosVendieron;
}

int Local :: maximoDeCombosVendidos(){
        int cantEmpleados = empleadosQueMasPedidosVendieron().longitud(),i=0;
        int max = cantidadDeCombosQueVendio(empleadosQueMasPedidosVendieron().iesimo(0));
        while(i<cantEmpleados-2){
            max = elMaximoDe(max, cantidadDeCombosQueVendio(empleadosQueMasPedidosVendieron().iesimo(i+1)) );
        i++;
        }
        return max;


}


int Local :: cantidadDeCombosQueVendio(const Empleado e){
    int cantPedidos = _ventas.longitud(),i = 0;
    int cantidadDeCombos = 0;
    while(i<cantPedidos){
        if(e == _ventas.iesimo(i).atendioP()){
            cantidadDeCombos = cantidadDeCombos + _ventas.iesimo(i).combosP().longitud();
        }
        i++;
    }
    return cantidadDeCombos;
}


Lista<Empleado> Local :: empleadosQueMasPedidosVendieron(){
    int cantEmpleados = empleadosL().longitud(),i=0;
    Lista<Empleado> losQueMasPedidosVendieron;
    while(i<cantEmpleados){
        if(empleadosQueVendieron().cantidadDeApariciones(empleadosL().iesimo(i)) == maximoDePedidosVendidos()){
                losQueMasPedidosVendieron.agregarAtras(empleadosL().iesimo(i));
        }
        i++;
    }
    return losQueMasPedidosVendieron;

}


int Local :: maximoDePedidosVendidos(){
    int i = 0,cantEmpleados = empleadosL().longitud();
    int max = empleadosQueVendieron().cantidadDeApariciones(empleadosL().iesimo(0));
    while(i<cantEmpleados-2){
    max = elMaximoDe(max, empleadosQueVendieron().cantidadDeApariciones(empleadosL().iesimo(i+1)) );
    i++;
    }
    return max;
}

int Local :: elMaximoDe(const int a,const int b){
    int max;
    if (a < b){
        max = b;
    }else{
        max = a;
    }
    return max;
}

void Local :: sancionL(const Empleado e, const Energia n){
   	int i = 0, cantEmpleados = _empleados.longitud();
    Lista< pair<Empleado,Energia> > losEmpleados;
    pair<Empleado,Energia> emp_ene;

    while(i<cantEmpleados){
		emp_ene.first = _empleados.iesimo(i).first;
        if(_empleados.iesimo(i).first==e){
			emp_ene.second = energiaEmpleadoL(e) - n;
        }else{
			emp_ene.second = energiaEmpleadoL(e);
        }
        losEmpleados.agregarAtras(emp_ene);
        i++;
    }
    _empleados = losEmpleados;
}

Empleado Local :: elVagonetaL(){
	int i = 0, cantEmpleados = _empleados.longitud(), j = 1;
	Empleado empleado;
	Lista <pair <Empleado, Energia> > listaEmpleados = _empleados;

		while (j < cantEmpleados){

			if (descansoMaximo(listaEmpleados.iesimo(i).first) >= descansoMaximo(listaEmpleados.iesimo(j).first)){
				empleado = listaEmpleados.iesimo(i).first;
				listaEmpleados.eliminarPosicion(j);
			}else{
				empleado = listaEmpleados.iesimo(j).first;
				listaEmpleados.eliminarPosicion(i);
			}
		cantEmpleados = cantEmpleados - 1;
		}

		if (j == cantEmpleados){
		empleado = listaEmpleados.iesimo(i).first;


		}

	return empleado;
}


int Local :: descansoMaximo(Empleado empleado){
	int i = 0, j = 1, cantDescansos = descansos(empleado).longitud(), elDescansoMaximo;
	Lista < int > listaDescansos = descansos(empleado);

		while (j < cantDescansos){
			if (listaDescansos.iesimo(i) >= listaDescansos.iesimo(j)){
				elDescansoMaximo = listaDescansos.iesimo(i);
				listaDescansos.eliminarPosicion(j);
			}else{
				elDescansoMaximo = listaDescansos.iesimo(j);
				listaDescansos.eliminarPosicion(i);
			}
		cantDescansos = cantDescansos - 1;
		}

		if (j == cantDescansos){
            elDescansoMaximo = listaDescansos.iesimo(i);

		}

	return elDescansoMaximo;
}

Lista < int > Local :: descansos(Empleado empleado){
	int i = 0, acum = 0, cantVentas = _ventas.longitud();
	Lista < Pedido > ventas = _ventas;
	Lista < int > losDescansos;

		while (i < cantVentas){

			if (_ventas.iesimo(i).atendioP() == empleado){
			losDescansos.agregar(acum);
			i++;
			acum = 0;
			}else{
				i++;
				acum++;
			}
		}

		if (i == cantVentas){
			losDescansos.agregar(acum);
			i++;
		}

	return losDescansos;
}

void Local :: anularPedidoL(int n){
        int i = 0;
        int actualizarStock;
        int energiaActual;
        Lista<Pedido> listaPedidos;
        Pedido p;
        Lista< pair<Bebida,Cantidad> > lasBebidas;
        pair <Bebida, Cantidad> beb_cant;
        Lista< pair<Hamburguesa,Cantidad> > losSanguches;
        pair <Hamburguesa, Cantidad> hamb_cant;
        Lista< pair<Empleado,Energia> > losEmpleados;
        pair<Empleado,Energia> emp_ene;

        while(i < _bebidas.longitud()){
                beb_cant.first = _bebidas.iesimo(i).first;
                actualizarStock = _bebidas.iesimo(i).second + cantidadBebidaEnElPedido(_bebidas.iesimo(i).first, _ventas.iesimo(n));
                beb_cant.second = actualizarStock;
                lasBebidas.agregarAtras(beb_cant);
                i++;
        }

        _bebidas = lasBebidas;

        i = 0;

        while(i < _sandwiches.longitud()){
                hamb_cant.first = _sandwiches.iesimo(i).first;
                actualizarStock = _sandwiches.iesimo(i).second + cantidadSangucheEnElPedido(_sandwiches.iesimo(i).first, _ventas.iesimo(n));
                hamb_cant.second = actualizarStock;
                losSanguches.agregarAtras(hamb_cant);
                i++;
        }

        _sandwiches = losSanguches;

        i = 0;
        while(i < _empleados.longitud()){
                emp_ene.first = _empleados.iesimo(i).first;
                energiaActual = _empleados.iesimo(i).second + miraEmpleadoSumaEnergia(_empleados.iesimo(i).first, n);
                emp_ene.second = energiaActual;
                losEmpleados.agregarAtras(emp_ene);
                i++;
        }

        _empleados = losEmpleados;


        i = 0;

        while(i < _ventas.longitud()){
                if(_ventas.iesimo(i).numeroP() != n ){
                        listaPedidos.agregarAtras(cambiarSoloNumeroP(_ventas.iesimo(i), n));
                }
                i++;
        }

        _ventas = listaPedidos;

}

Pedido  Local :: cambiarSoloNumeroP (const Pedido& p,const int n){
        int numPedido = p.numeroP();
        int actualizarNumero;



        if(p.numeroP() < n){
            actualizarNumero = p.numeroP();
        }else{
            actualizarNumero = p.numeroP()-1;
        }

        numPedido = actualizarNumero;

        Pedido ped(numPedido, p.atendioP(), p.combosP());
        return ped;
}

int Local :: miraEmpleadoSumaEnergia(Empleado emp, int n){
        int k = 0;
        int sumar = 0;
        Pedido p;
        while(n != _ventas.iesimo(k).numeroP()){
                k++;
        }
        p = _ventas.iesimo(n);

        if(emp == p.atendioP()){
                sumar = p.dificultadP();
        }
        return sumar;
}


void Local :: agregarComboAlPedidoL(const Combo c, int n){
	int i = 0;
	int actualizarStock;
	int energiaActual;
	Lista<Pedido> listaPedidos;
	Pedido p;
	Lista< pair<Bebida,Cantidad> > lasBebidas;
	pair <Bebida, Cantidad> beb_cant;
	Lista< pair<Hamburguesa,Cantidad> > losSanguches;
	pair <Hamburguesa, Cantidad> hamb_cant;
	Lista< pair<Empleado,Energia> > losEmpleados;
	pair<Empleado,Energia> emp_ene;

	while(_ventas.iesimo(i).numeroP() != n){
		listaPedidos.agregarAtras(_ventas.iesimo(i));
		i++;
	}

	p = _ventas.iesimo(i);

	Lista<Combo> listaCombo = p.combosP();

	listaCombo.agregarAtras(c);

	Pedido ped(p.numeroP(), p.atendioP(), listaCombo);

	listaPedidos.agregarAtras(ped);

	i++;

	while(i < _ventas.longitud()){
		listaPedidos.agregarAtras(_ventas.iesimo(i));
		i++;
	}

	_ventas = listaPedidos;

	i = 0;

	while(i < _bebidas.longitud()){
		beb_cant.first = _bebidas.iesimo(i).first;
		actualizarStock = _bebidas.iesimo(i).second - beta(_bebidas.iesimo(i).first == c.bebidaC());
		beb_cant.second = actualizarStock;
		lasBebidas.agregarAtras(beb_cant);
		i++;
	}

	_bebidas = lasBebidas;


	i = 0;
	while(i < _sandwiches.longitud()){
		hamb_cant.first = _sandwiches.iesimo(i).first;
		actualizarStock = _sandwiches.iesimo(i).second - beta(_sandwiches.iesimo(i).first == c.sandwichC());
		hamb_cant.second = actualizarStock;
		losSanguches.agregarAtras(hamb_cant);
		i++;
	}

	_sandwiches = losSanguches;

	i = 0;
	while(i < _empleados.longitud()){
		emp_ene.first = _empleados.iesimo(i).first;
		energiaActual = _empleados.iesimo(i).second - miraEmpleadoRestaEnergia(_empleados.iesimo(i).first, n, c);
		emp_ene.second = energiaActual;
		losEmpleados.agregarAtras(emp_ene);
		i++;
	}

	_empleados = losEmpleados;

}

int Local :: miraEmpleadoRestaEnergia(Empleado emp, int n, const Combo c){
	int k = 0;
	int restar = 0;
	Pedido p;
	while(n != _ventas.iesimo(k).numeroP()){
		k++;
	}
	p = _ventas.iesimo(k);

	if(emp == p.atendioP()){
		restar = c.dificultadC();
	}
	return restar;
}

int Local :: beta(bool b){
	int k = 0;
	if(b){
		k = 1;
	}
	return k;
}






void Local :: mostrar(std::ostream& os) const{
	int i = 0, cantBHE = _bebidas.longitud();
	os << "Las bebidas del local son: [";
	while(i< cantBHE){
		os << "(" <<_bebidas.iesimo(i).first <<"," << _bebidas.iesimo(i).second <<")";
		if(i<cantBHE-1){
			os << ",";
		}
		i++;
	}
	os << "]" << endl;


	i = 0, cantBHE = _sandwiches.longitud();
	os << "Los sanguches del local son: [";
	while(i< cantBHE){
		os << "(" <<_sandwiches.iesimo(i).first <<"," << _sandwiches.iesimo(i).second <<")";
		if(i<cantBHE-1){
			os << ",";
		}
		i++;
	}
	os << "]" << endl;

	i = 0, cantBHE = _empleados.longitud();
	os << "Los empleados del local son: [";
	while(i < cantBHE){
		os << "(" <<_empleados.iesimo(i).first <<"," << _empleados.iesimo(i).second <<")";
		if(i<cantBHE-1){
			os << ",";
		}
		i++;
	}
	os << "]" << endl;

	os << "Las ventas del local son: " << _ventas << endl;
}

void Local :: guardar(std::ostream& os) const{
		int i = 0, cantBHEV =  _bebidas.longitud();
		os << "L [";
		while(i<cantBHEV){
			os << "(|" << _bebidas.iesimo(i).first << "|," << _bebidas.iesimo(i).second << ")";
			if(i<cantBHEV-1){
				os << ",";
			}
			i++;
		}
		os << "]" << endl;

		i = 0, cantBHEV =  _sandwiches.longitud();
		os << "[";
		while(i<cantBHEV){
			os << "(|" << _sandwiches.iesimo(i).first << "|," << _sandwiches.iesimo(i).second << ")";
			if(i<cantBHEV-1){
				os << ",";
			}
			i++;
		}
		os << "]" << endl;

		i = 0, cantBHEV =  _empleados.longitud();
		os << "[";
		while(i<cantBHEV){
			os << "(|" << _empleados.iesimo(i).first << "|," << _empleados.iesimo(i).second << ")";
			if(i<cantBHEV-1){
				os << ",";
			}
			i++;
		}
		os << "]" << endl;

		i = 0, cantBHEV =  _ventas.longitud();
		os << "[";
		while(i<cantBHEV){
			os << "(";
			_ventas.iesimo(i).guardar(os);
			os << ")";
			if(i<cantBHEV-1){
				os <<",";
			}
			i++;
		}
		os << "]";
}

void Local :: cargar (std::istream& is){}

std::ostream & operator<<(std::ostream & os,const Local & c){
	c.mostrar(os);
	return os;
}
